AddCSLuaFile( "shared.lua" )
AddCSLuaFile( "cl_init.lua" )
AddCSLuaFile( "cl_command.lua" )
include( 'shared.lua' )
include( 'sv_tables.lua' )
include( 'sv_client.lua' )
include( 'sv_rounds.lua' )
include( 'sv_admin.lua' )

GM.Rounds = CreateConVar( "gjail_rounds", "10", FCVAR_ARCHIVE )

local MapStart = true
/*---------------------------------------------------------
   Name: gamemode:EntityKeyValue( ent, key, value )
   Desc: Called when an entity has a keyvalue set
	      Returning a string it will override the value
---------------------------------------------------------*/
function GM:EntityKeyValue( ent, key, value )
	if not MapStart then return end
	if table.HasValue(self.ProofClass, ent:GetClass()) then return end
	if not ent.K then ent.K = {} end
	table.insert(ent.K, {key, value})
end

/*---------------------------------------------------------
   Name: gamemode:InitPostEntity( )
   Desc: Called as soon as all map entities have been spawned
---------------------------------------------------------*/
GM.NextMap = nil
GM.BrkTbl = {}
function GM:InitPostEntity( )
	MapStart = false
	for _, ent in pairs( ents.FindByClass( "weapon_*" ) ) do
		if ent:IsValid() then
			ent:Remove()
			ent.NoCopy = true
		end
	end
	for _, ent in pairs( ents.FindByClass( "game_player_equip" ) ) do
		if ent:IsValid() then
			ent:Remove()
			ent.NoCopy = true
		end
	end
	for _, ent in pairs( ents.GetAll() ) do
		if ent:IsValid() and not table.HasValue(self.ProofClass, ent:GetClass()) and not ent.NoCopy then
			local tab = {}
			tab.Class = ent:GetClass()
			tab.Pos = ent:GetPos()
			tab.Angle = ent:GetAngles()
			tab.Model = ent:GetModel()
			tab.K = {}
			if ent.K then
				table.Merge(tab.K, ent.K)
			end
			table.insert(self.BrkTbl, tab)
			ent.RndRemove = true
		end
	end
	if file.Exists("gjail/"..game.GetMap()..".txt") then
		self.MapFile = util.KeyValuesToTable( file.Read("gjail/"..game.GetMap()..".txt") )
		for _, entt in pairs(self.MapFile.weapons) do
			entt = string.Explode(" ", entt)
			local ent = ents.Create(entt[1])
			ent:SetPos(Vector(entt[2], entt[3], entt[4]))
			ent:Spawn()
			ent:Activate()
		end
	end
	if self.Rounds:GetInt() > 0 and file.Exists("gjail/map_cycle.txt") then
		local MapList = util.KeyValuesToTable(file.Read("gjail/map_cycle.txt"))
		local First = nil
		local Next = nil
		for _,v in pairs(MapList) do
			if not First then First = v end
			if Next then self.NextMap = v break end
			if v == game.GetMap() then
				Next = true
			end
		end
		if not self.NextMap then
			self.NextMap = First
		end
	end
end

/*---------------------------------------------------------
   Name: gamemode:DoPlayerDeath( )
   Desc: Carries out actions when the player dies 		 
---------------------------------------------------------*/
function GM:DoPlayerDeath( ply, attacker, dmginfo )
	if ply:GetActiveWeapon():IsValid()
	and not table.HasValue(self.DoNotDrop, ply:GetActiveWeapon():GetClass()) then
		ply:DropWeapon( ply:GetActiveWeapon() )
	end
	if ply:Team() == TEAM_GUARD or ply:Team() == TEAM_PRISONER then
		local rag = ents.Create("prop_ragdoll")
		rag:SetPos(ply:GetPos())
		rag:SetAngles(ply:GetAngles())
		rag:SetModel(ply:GetModel())
		rag:SetVelocity(ply:GetVelocity())
		rag:SetCollisionGroup(COLLISION_GROUP_DEBRIS)
		rag:Spawn()
		rag:Activate()
	else 
		return false 
	end

	ply.SpawnSpecPos = ply:GetPos() + Vector(0,0,64)
	ply.SpawnSpecAng = ply:GetAimVector():Angle()
	ply:AddDeaths( 1 )
	
	if ( attacker:IsValid() && attacker:IsPlayer() ) then
		if ( attacker == ply ) then
			attacker:AddFrags( -1 )
		else
			attacker:AddFrags( 1 )
		end
	end

	if ply:Team() == TEAM_GUARD then
		ply:SetTeam(TEAM_GUARD_DEAD) end
	if ply:Team() == TEAM_PRISONER then
		ply:SetTeam(TEAM_PRISONER_DEAD) end
end

/*---------------------------------------------------------
   Name: gamemode:PlayerSpawn( )
   Desc: Called when a player spawns
---------------------------------------------------------*/
function GM:PlayerSpawn( pl )
	pl.Disguise = false
	pl:StripWeapons()
	pl:StripAmmo()
	if pl:Team() == TEAM_SPECTATOR or pl:Team() >= TEAM_GUARD_DEAD then
		self:PlayerSpawnAsSpectator( pl )
		return
	end
	pl:UnSpectate()
	hook.Call( "PlayerLoadout", GAMEMODE, pl )
	hook.Call( "PlayerSetModel", GAMEMODE, pl )
end

/*---------------------------------------------------------
   Name: gamemode:PlayerDeathThink( player )
   Desc: Called when the player is waiting to respawn
---------------------------------------------------------*/
function GM:PlayerDeathThink( pl )
	pl:Spawn()
end

/*---------------------------------------------------------
   Name: gamemode:PlayerShouldTakeDamage
   Return true if this player should take damage from this attacker
---------------------------------------------------------*/
function GM:PlayerShouldTakeDamage( ply, attacker )
	if attacker:IsValid() and attacker:IsPlayer() then
		return ply:Team() ~= attacker:Team()
	else
		return true
	end
end

/*---------------------------------------------------------
   Name: gamemode:PlayerInitialSpawn( )
   Desc: Called just before the player's first spawn
---------------------------------------------------------*/
function GM:PlayerInitialSpawn( pl )
	pl:SetTeam( TEAM_SPECTATOR )
end

/*---------------------------------------------------------
   Name: gamemode:PlayerSpawnAsSpectator( )
   Desc: Player spawns as a spectator
---------------------------------------------------------*/
function GM:PlayerSpawnAsSpectator( pl )
	pl:Spectate( OBS_MODE_ROAMING )
	if pl.SpawnSpecPos then
		pl:SetPos(pl.SpawnSpecPos)
		pl:SetEyeAngles(pl.SpawnSpecAng)
		pl.SpawnSpecPos = nil
		pl.SpawnSpecAng = nil
	end
end

/*---------------------------------------------------------
   Name: gamemode:PlayerSetModel( )
   Desc: Set the player's model
---------------------------------------------------------*/
function GM:PlayerSetModel( pl )
	local Mdl = ""
	local team = pl:Team()
	if team == TEAM_PRISONER then
		local Rand = math.random(1, #(self.PMdl))
	    Mdl = self.PMdl[Rand]
	elseif team == TEAM_GUARD then
		local Rand = math.random(1, #(self.GMdl))
	    Mdl = self.GMdl[Rand]
	end
	util.PrecacheModel( "models/player/"..Mdl..".mdl" )
	pl:SetModel( "models/player/"..Mdl..".mdl" )
end

/*---------------------------------------------------------
   Name: gamemode:GiveWeap( ply )
   Desc: Give a random weapon
---------------------------------------------------------*/
function GM:GivePWeap( pl )
	local Rand = math.random(1, 40)
	if Rand <= 4 then
		pl:Give("weapon_pickpocket")
	elseif Rand <= 7 then
		pl:Give("weapon_seringue_de_drogue")
	elseif Rand <= 9 then
		pl:Give("weapon_flash")
	elseif Rand <= 10 then
		pl:Give("weapon_gun_du_taulard")
	end
end

function GM:GiveGWeap( pl )
	local Rand = math.random(1, 10)
	if Rand <= 6 then
		pl:Give("weapon_m4a1_rifle")
	elseif Rand <= 8 then
		pl:Give("weapon_aug_rifle")
	else
		pl:Give("weapon_famas_rifle")
	end
end

/*---------------------------------------------------------
   Name: gamemode:PlayerLoadout( ply )
   Desc: Give the player the default spawning weapons/ammo
---------------------------------------------------------*/
function GM:PlayerLoadout( pl )
	pl:SetHealth(100)
	pl:SetWalkSpeed(250) 
	pl.Regen = nil
	pl:SprintDisable()
	if pl:IsAdmin() then
		pl:Give( "weapon_physgun" )
	end
	pl:GiveAmmo( 30, "XBowBolt", true )
	pl:GiveAmmo( 50, "Pistol", true )
	pl:GiveAmmo( 100, "SMG1", true )
	pl:Give( "weapon_couteau" )
	local team = pl:Team()
	if team == TEAM_PRISONER then
		pl:Give( "weapon_mains" )
		self:GivePWeap(pl)
		pl:SelectWeapon( "weapon_mains" )
		pl:SetArmor(0)
 		pl:SetRunSpeed(300)
	elseif team == TEAM_GUARD then
		pl:Give( "weapon_mains" )
		pl:Give( "weapon_tranquiliseur" )
		pl:Give( "weapon_pistolet_du_gardien" )
		self:GiveGWeap(pl)
		pl:SelectWeapon( "weapon_mains" )
		pl:SetArmor(10)
 		pl:SetRunSpeed(250)
	end
end

/*---------------------------------------------------------
   Name: gamemode:PlayerCanPickupWeapon( )
   Desc: Called when a player tries to pickup a weapon.
		  return true to allow the pickup.
---------------------------------------------------------*/
function GM:PlayerCanPickupWeapon( player, entity )
	if player:Team() == TEAM_GUARD
	and entity:GetClass() == "weapon_costume" then return false end
	if player:HasWeapon(entity:GetClass()) then return false end
	if table.HasValue(self.WeapGroup_Pistol, entity:GetClass()) then
		for _,v in pairs(self.WeapGroup_Pistol) do
			if player:HasWeapon(v) then return false end
		end
	end
	if table.HasValue(self.WeapGroup_Rifle, entity:GetClass()) then
		for _,v in pairs(self.WeapGroup_Rifle) do
			if player:HasWeapon(v) then return false end
		end
	end
	return true
end

/*---------------------------------------------------------
   Health regeneration
---------------------------------------------------------*/
function EntityTakeDamage( ent )
	if ( ent:IsPlayer() ) then
		ent.Regen = CurTime() + 5
	end
end
hook.Add("EntityTakeDamage", "GJail_EntityTakeDamage", EntityTakeDamage)

local RegenTime = 0
local function Regen()
	local CT = CurTime()
	if RegenTime < CT then
		RegenTime = CT + 1
		for _, ply in pairs(player.GetAll()) do
			if ply:Alive() and (ply.Regen or 0) < CT and ply:Health() < 100 then
				ply:SetHealth(ply:Health() + 1)
			end
		end
	end
end
hook.Add("Think", "GJail_Regen", Regen)

/*---------------------------------------------------------
   Name: gamemode:PlayerNoClip( player, bool )
   Desc: Player pressed the noclip key, return true if
		  the player is allowed to noclip, false to block
---------------------------------------------------------*/
function GM:PlayerNoClip( ply )
	return ply:IsAdmin()
end

/*---------------------------------------------------------
   Name: gamemode:PlayerUse( player, entity )
   Desc: Player pressed use key
---------------------------------------------------------*/
local function PlayerUse( pl )
	if pl:Team() == TEAM_SPECTATOR or pl:Team() >= TEAM_GUARD_DEAD then
		return false
	end
end
hook.Add("PlayerUse", "GJail_PlayerUse", PlayerUse)